package com.geqian.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geqian.common.common.PageRequest;
import com.geqian.common.common.PageResult;
import com.geqian.common.common.ResponseResult;
import com.geqian.web.annotation.CustomTransaction;
import com.geqian.web.entity.Menu;
import com.geqian.web.entity.RoleMenu;
import com.geqian.web.mapper.MenuMapper;
import com.geqian.web.mapper.RoleMapper;
import com.geqian.web.mapper.RoleMenuMapper;
import com.geqian.web.pojo.SimpleMenu;
import com.geqian.web.pojo.MenuQuery;
import com.geqian.web.service.MenuService;
import com.geqian.web.utils.JwtUtils;
import com.geqian.web.utils.PageUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【sys_menu(菜单表)】的数据库操作Service实现
 * @createDate 2023-04-09 17:19:22
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {


    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private RoleMapper roleMapper;


    private final Map<Integer, String> error = new HashMap<>();


    @PostConstruct
    private void init() {
        error.put(0, "请确保权限标识唯一");
        error.put(1, "请确保路由路径、路由名称、权限标识、组件名称唯一");
        error.put(2, "请确保权限标识唯一");
    }


    @Override
    public ResponseResult<List<Menu>> getMenuList(String token) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        MenuQuery menuQuery = new MenuQuery();
        menuQuery.setUserId(Long.valueOf(userId));
        if (!Objects.equals(userId, "1")) {
            menuQuery.setStatus(0);
        } else {
            menuQuery.setVisible(0);
        }
        List<Menu> menuList = this.baseMapper.selectMenuList(menuQuery);
        if (!CollectionUtils.isEmpty(menuList)) {
            menuList = menuList.stream().sorted(Comparator.comparingInt(Menu::getOrderBy)).collect(Collectors.toList());
            List<Menu> topLeveMenuList = menuList.stream().filter(menu -> menu.getParentId() == 0).collect(Collectors.toList());
            for (Menu topLeveMenu : topLeveMenuList) {
                topLeveMenu.setChildren(getChildrenMenu(menuList, topLeveMenu.getMenuId()));
            }
            return ResponseResult.success(topLeveMenuList);
        }
        return ResponseResult.success(new ArrayList<>());

    }

    @Override
    public ResponseResult<PageResult<Menu>> getMenuPageList(String token, PageRequest pageRequest) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        List<Menu> menuList;
        List<Menu> topLeveMenuList;
        MenuQuery menuQuery = new MenuQuery();
        menuQuery.setUserId(Long.valueOf(userId));
        if (StringUtils.hasText(pageRequest.getKey())) {
            menuList = this.baseMapper.selectMenuList(menuQuery).stream()
                    .sorted(Comparator.comparingInt(Menu::getOrderBy))
                    .collect(Collectors.toList());
            PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
            menuQuery.setParentId(0);
            menuQuery.setLabel(pageRequest.getKey());
            topLeveMenuList = this.baseMapper.selectMenuList(menuQuery);
        } else {
            menuList = this.baseMapper.selectMenuList(menuQuery).stream().sorted(Comparator.comparingInt(Menu::getOrderBy)).collect(Collectors.toList());
            PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
            menuQuery.setParentId(0);
            topLeveMenuList = this.baseMapper.selectMenuList(menuQuery);
        }
        topLeveMenuList = topLeveMenuList.stream().sorted(Comparator.comparingInt(Menu::getOrderBy)).collect(Collectors.toList());
        PageInfo<Menu> pageInfo = new PageInfo<>(topLeveMenuList);
        PageResult<Menu> pageResult = PageUtils.getPageResult(pageInfo);
        for (Menu topLeveMenu : pageResult.getDataList()) {
            topLeveMenu.setChildren(getChildrenMenu(menuList, topLeveMenu.getMenuId()));
        }
        return ResponseResult.success(pageResult);
    }

    @Override
    public ResponseResult<Object> updateMenu(Menu menu, String token) {
        try {
            if (Objects.nonNull(menu)) {
                String userId = JwtUtils.parseForValue(token, "userId", String.class);
                menu.setUpdateTime(new Date());
                menu.setUpdateBy(Long.valueOf(userId));
                this.baseMapper.updateById(menu);
            }
        } catch (DuplicateKeyException e) {
            e.printStackTrace();
            return ResponseResult.fail(error.get(menu.getMenuType()));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail(e.getMessage());
        }
        return ResponseResult.success();
    }


    @CustomTransaction
    @Override
    public ResponseResult<Object> addMenu(Menu menu, String token) {
        try {
            if (StringUtils.hasText(token)) {
                String userId = JwtUtils.parseForValue(token, "userId", String.class);
                if (Objects.nonNull(menu)) {
                    menu.setCreateBy(Long.valueOf(userId));
                    menu.setUpdateBy(Long.valueOf(userId));
                    Date date = new Date();
                    menu.setUpdateTime(date);
                    menu.setCreateTime(date);
                    List<Long> roleIdList = roleMapper.selectRoleIdList(Long.valueOf(userId));
                    this.baseMapper.insertReturnMenuId(menu);
                    for (Long roleId : roleIdList) {
                        RoleMenu roleMenu = new RoleMenu();
                        roleMenu.setRoleId(roleId);
                        roleMenu.setMenuId(menu.getMenuId());
                        roleMenuMapper.insert(roleMenu);
                    }
                }
            }
        } catch (DuplicateKeyException e) {
            e.printStackTrace();
            return ResponseResult.fail(error.get(menu.getMenuType()));
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return ResponseResult.fail(e.getMessage());
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult<List<SimpleMenu>> getDirMenuList(String token) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        List<SimpleMenu> dirMenuList = this.baseMapper.selectDirMenuList(Long.valueOf(userId));
        if (!CollectionUtils.isEmpty(dirMenuList)) {
            List<SimpleMenu> topLeveMenuDirList = dirMenuList.stream().filter(menu -> Objects.equals(menu.getParentId(), "0")).collect(Collectors.toList());
            for (SimpleMenu topLeveMenuDir : topLeveMenuDirList) {
                topLeveMenuDir.setChildren(getChildrenMenu(dirMenuList, topLeveMenuDir.getMenuId()));
            }
            SimpleMenu simpleMenu = new SimpleMenu();
            simpleMenu.setMenuId("0");
            simpleMenu.setLabel("一级目录");
            simpleMenu.setChildren(topLeveMenuDirList);
            return ResponseResult.success(Collections.singletonList(simpleMenu));
        }
        return ResponseResult.success(new ArrayList<>());
    }

    @Override
    public ResponseResult<List<SimpleMenu>> getComponentMenuList(String token) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        List<SimpleMenu> componentDirList = this.baseMapper.selectComponentMenuList(Long.valueOf(userId));
        if (!CollectionUtils.isEmpty(componentDirList)) {
            List<SimpleMenu> topLeveMenuDirList = componentDirList.stream().filter(menu -> Objects.equals(menu.getParentId(), "0")).collect(Collectors.toList());
            for (SimpleMenu topLeveMenuDir : topLeveMenuDirList) {
                topLeveMenuDir.setChildren(getChildrenMenu(componentDirList, topLeveMenuDir.getMenuId()));
            }
            SimpleMenu directoryMenu = new SimpleMenu();
            directoryMenu.setMenuId("0");
            directoryMenu.setLabel("一级目录");
            directoryMenu.setChildren(topLeveMenuDirList);
            return ResponseResult.success(Collections.singletonList(directoryMenu));
        }
        return ResponseResult.success(new ArrayList<>());
    }


    @Override
    @CustomTransaction
    public ResponseResult<Object> deleteMenu(Long menuId) {
        if (Objects.nonNull(menuId)) {
            boolean flag = hashChildren(menuId);
            if (flag) {
                return ResponseResult.fail("当前菜单存在子菜单，请先删除子菜单");
            }
            //删除菜单
            this.baseMapper.deleteById(menuId);

            //删除分配给角色的该菜单
            LambdaQueryWrapper<RoleMenu> roleMenuWrapper = new LambdaQueryWrapper<>();
            roleMenuWrapper.eq(RoleMenu::getMenuId, menuId);
            roleMenuMapper.delete(roleMenuWrapper);
        }
        return ResponseResult.success();
    }


    @Override
    public ResponseResult<List<Menu>> getMenuAllList() {
        List<Menu> menuList = this.baseMapper.selectList(null);
        if (!CollectionUtils.isEmpty(menuList)) {
            menuList = menuList.stream().sorted(Comparator.comparingInt(Menu::getOrderBy)).collect(Collectors.toList());
            List<Menu> topLeveMenuList = menuList.stream().filter(menu -> menu.getParentId() == 0).collect(Collectors.toList());
            for (Menu topLeveMenu : topLeveMenuList) {
                topLeveMenu.setChildren(getChildrenMenu(menuList, topLeveMenu.getMenuId()));
            }
            return ResponseResult.success(topLeveMenuList);
        }
        return ResponseResult.success(new ArrayList<>());
    }


    private List<SimpleMenu> getChildrenMenu(List<SimpleMenu> dirMenuList, String menuId) {
        List<SimpleMenu> nextLevelMenuList = dirMenuList.stream().filter(menu -> Objects.equals(menu.getParentId(), menuId)).collect(Collectors.toList());
        for (SimpleMenu nextLevelMenu : nextLevelMenuList) {
            nextLevelMenu.setChildren(getChildrenMenu(dirMenuList, nextLevelMenu.getMenuId()));
        }
        return nextLevelMenuList;
    }

    private List<Menu> getChildrenMenu(List<Menu> menuList, long menuId) {
        List<Menu> nextLevelMenuList = menuList.stream().filter(menu -> menu.getParentId() == menuId).collect(Collectors.toList());
        for (Menu nextLevelMenu : nextLevelMenuList) {
            nextLevelMenu.setChildren(getChildrenMenu(menuList, nextLevelMenu.getMenuId()));
        }
        return nextLevelMenuList;
    }


    private boolean hashChildren(Long menuId) {
        LambdaQueryWrapper<Menu> wrapper = Wrappers.lambdaQuery(Menu.class);
        wrapper.eq(Menu::getParentId, menuId);
        List<Menu> menuList = this.baseMapper.selectList(wrapper);
        return menuList.size() > 0;
    }

}




